home *** CD-ROM | disk | FTP | other *** search
- export
- modalHarmonize,
- chordHarmonize,
- parallelHarmonize,
- majorHarmonize
- end
-
- #
- # closed voicing harmonization.
- #
- # Routines here basically give closed voicings via
- # a harmonization of a high melody voice. No attention
- # is paid to voice leading from previous chord.
- #
- # routines for harmonizing a melody note
- #
- # 1. modalHarmonize - produce chord in scale that corresponds to
- # modal harmony; e.g., given B in C IONIAN scale returns Major7, C,E,G,B
- # given C in C IONIAN scale returns Dminor7,
- # LD,LF,LA,C.
- # Can handle modal scales only.
- #
- # 2. chordHarmonize - harmonize melody note according to current chord.
- # chord passed in is used and may be inverted.
- # Handles most (if not all) chords.
- #
- # 3. parallelHarmonize - Parallel motion may be supported
- # by saving the last melody note
- # and the last returned harmony chord and then subtracing the
- # difference between the new melody note and last melody note
- # to produce the new harmony chord. A routine is provided to do this.
- #
- # 4. majorHarmonize - harmonizes melody note based on root I ii iii IV V vi vii0
- # harmonic assumption. Thus if used be careful of harmonic
- # root; e.g., if tracking via chord then harmonize as follows;
- #
- # major - I, IV
- # minor - ii, iii, vi
- # dom - V
- # dim - vii0
- #
- # 5. harmonizeDominant() - different close harmony for dominant - uses
- # flatted 5th rule (dom7 on minor 2nd of root). NOT IMPLEMENTED.
- #
- # 6. minorHarmonize - similar to majorHarmonize but use traditional
- # minor chords. NOT IMPLEMENTED.
-
- # turn on for standalone test
- # otherwise include these two before this include library.
- @include \mh\scales.mh
- @include \mh\chords.mh
-
- #
- # modalHarmonize()
- #
- # Given the following inputs:
- # pointer to integer output array of size 3
- # scaleCount - number of indices into scale array
- # pointer to scale array
- # root offset - i.e., offset value for current note
- # where note is formed by octave+root+offset
- #
- # produce a "harmony" chord from the inputs.
- # We find the associated "offsets" down a third, fifth,
- # and seventh from the input offset which is assumed to
- # be the top melody note.
- #
- # The returned offsets taken together with the input offset
- # can be used to form a 4 note harmonized chord. This
- # will be built from the associated scale and thus represents
- # a simple harmonization. The chord is built as follows:
- # melody = octave+root+offset
- # third down = octave+root+output[2]
- # fifth down = octave+root+output[1]
- # seventh down = octave+root+output[0]
- #
- # CAVEATS:
- # This routine makes sense for normal scales. If
- # the scales are far out; so will be the results.
- #
- # It also isn't very interesting to call this over
- # and over again for a harmonization. The
- # high level routines may use this as a basic tool,
- # but should also use a certain amount of diminished
- # and/or same chord (if Dom7, then use Dom7) to
- # provide variety.
- #
- # Also:
- # . not suitable for 1st/last note in chord.
- # . not normal for "thickened" line.
- #
-
- riff modalHarmonize(int vector output, scaleCount, vector scale, offset)
- # vector output, lower 3 notes of chord, 4 voice chord including top note
- # note that this must be an integer vector due to negative
- # subtraction trick, below.
- # scale index
- # note offset (note is assumed to be octave+root+rootOffset)
- int thirdOffset
- int fifthOffset
- int seventhOffset
- int i
-
- # find offset value
- for ( i = 0; i < scaleCount; i++)
- if (scale[i] == offset)
- break
- end
- end
- # ASSERTION
- if ( i == scaleCount)
- void printf("did not find rootOffset in scale\n")
- return(0)
- end
- # i is associated scale index
-
- # first third down
- thirdOffset = i - 2
- if (thirdOffset < 0)
- thirdOffset = scaleCount + thirdOffset
- output[2] = scale[thirdOffset] - 12
- else
- output[2] = scale[thirdOffset]
- end
-
- # fifth down
- fifthOffset = i - 4
- if (fifthOffset < 0)
- fifthOffset = scaleCount + fifthOffset
- output[1] = scale[fifthOffset] - 12
- else
- output[1] = scale[fifthOffset]
- end
-
- # 7th down
- seventhOffset = i - 6
- if (seventhOffset < 0)
- seventhOffset = scaleCount + seventhOffset
- output[0] = scale[seventhOffset] - 12
- else
- output[0] = scale[seventhOffset]
- end
- end
-
- #
- # chordHarmonize()
- # harmonize a melody note to a certain CHORD pattern
- #
- # returns chord with ROOT; E.g., if C chord and D melody
- # note; you get back a harmony chord in closed position
- # that has a C root. The chord maybe inverted. The chord
- # notes are chosen as close as possible down from
- # the melody note. No attention is giving to voice leading.
- #
- # Can handle 2,3,and more note chords. If chord is bigger
- # than 3 notes; the chordSize is used for determining lower
- # offsets returned.
- #
- riff chordHarmonize(int vector output, melOffset, vector chordInput, chordSize)
- # output - array for 3 three lower harmony voices
- # melOffset - (octave,root,offset) form of lead melody note.
- # vector chordInput - row pointer to chord in chordNotes array.
- # chordSize - max notes in chord.
- #
- # returns:
- # number of notes used in output array. E.g., 3 means
- # 3 voice chord. 2 means 2 voice chord.
- int chordIndex
- int noback
-
- # map offset into chord index
- # we find first chord degree greater than or equal to
- # melody offset
- for ( chordIndex = 0; chordIndex < chordSize; chordIndex++)
- if (chordInput[chordIndex] >= melOffset)
- break
- end
- end
- if (chordIndex == chordSize)
- chordIndex--
- end
- #void printf("chordSize %d, chordIndex %d [] %d, melOffset %d\n", chordSize, chordIndex, chordInput[chordIndex], melOffset)
- # chordIndex is first chord degree GREATER than or same as melody note
- # this means that previous chord degree is less than melody note.
-
- switch(chordSize)
- # 2 note chords
- case 2:
- noback = 3 - chordIndex
- switch(noback)
- # 0 can't happen
- case 1:
- output[2] = chordInput[1]
- output[1] = chordInput[0] # unison
- output[0] = chordInput[1] - 12
- end
- case 2:
- output[2] = chordInput[0] # unison
- output[1] = chordInput[1] - 12
- output[0] = chordInput[0] - 12
- end
- # complete octave down
- case 3:
- output[2] = chordInput[1] - 12
- output[1] = chordInput[0] - 12
- output[0] = chordInput[1] - 24
- end
- default:
- void printf("%d %d invalid interval calculation\n",chordSize,chordIndex)
- end
-
- end
- end
- # 3 note chords
- case 3:
- noback = 3 - chordIndex
- switch(noback)
- case 0:
- output[2] = chordInput[2] # 5th
- output[1] = chordInput[1] # 3rd
- output[0] = chordInput[0] # unison
- end
- case 1:
- output[2] = chordInput[1] # 3rd
- output[1] = chordInput[0] # unison
- output[0] = chordInput[2] - 12 # 5th
- end
- case 2:
- output[2] = chordInput[0] # unison
- output[1] = chordInput[2] - 12 # 5th
- output[0] = chordInput[1] - 12 # 3rd
- end
- # complete octave down
- case 3:
- output[2] = chordInput[2] - 12 # 5th
- output[1] = chordInput[1] - 12 # 3rd
- output[0] = chordInput[0] - 12 # unison
- end
- default:
- void printf("%d %d invalid interval calculation\n",chordSize,chordIndex)
- end
-
- end
- end
- # more than 3
- default:
- noback = 3 - chordIndex
- switch(noback)
- case 0:
- output[2] = chordInput[2] # 5th
- output[1] = chordInput[1] # 3rd
- output[0] = chordInput[0] # unison
- end
- case 1:
- output[2] = chordInput[1] # 3rd
- output[1] = chordInput[0] # unison
- output[0] = chordInput[chordSize-1] - 12 # 7th
- end
- case 2:
- output[2] = chordInput[0] # unison
- output[1] = chordInput[chordSize-1] - 12 # 7th
- output[0] = chordInput[chordSize-2] - 12 # 5rd
- end
- # complete octave down
- case 3:
- output[2] = chordInput[chordSize-1] - 12 # 7th
- output[1] = chordInput[chordSize-2] - 12 # 5th
- output[0] = chordInput[chordSize-3] - 12 # 3rd
- end
- default:
- void printf("%d %d invalid interval calculation\n",chordSize,chordIndex)
- end
-
- end
- end
- end
- end
-
- #
- # parallelHarmonize()
- #
- # return parallel harmony chord.
- #
- # Caveats:
- # You can't do it on the first chord obviousally
- #
- # difference. positive or negative offset from previous melody note
- # e.g., C -> D, then 2, C -> LBb then -2. should be new - old.
- riff parallelHarmonize(int vector output, melOffset, difference)
- output[0] = output[0] + difference
- output[1] = output[1] + difference
- output[2] = output[2] + difference
- return(melOffset+difference)
- end
-
- #
- # majorHarmonize
- #
- # expect offset that corresponds to major scale offsets.
- # returns harmony chord based on standard major root harmony.
- # I ii iii IV V vi vii0.
- #
- # Chords returned are basically either major or dominant
- # harmony (not too racy here).
- #
- riff majorHarmonize(int vector output, offset)
- # vector output, lower 3 notes of chord, 4 voice chord including top note
- # note that this must be an integer vector due to negative
- # subtraction trick, below.
- # offset - IONIAN scale offset 0,2,4,5,7,9,11
- # (unison)0 - returns major chord
- # (2nd) 2 - returns vii0 OR V7 (random)
- # (3rd) 4 - returns major chord
- # (4th) 5 - returns vii0 or V7
- # (5th) 7 - returns major
- # (6th) 9 - returns vii0/ii
- # (7th) 11 - returns major
- #
- int rval
- rval = mchoose(0,1)
- switch(offset)
- # unison, return Major inverted on 3rd
- case 0:
- output[0] = {-8} # third
- output[1] = {-5} # fifth
- if (rval)
- output[2] = {-3} # sixth
- else
- output[2] = {-1} # seventh
- end
- end
- # 2nd, return Dom7 or vii0 half/dim.
- # Dom7 is inverted on 7th, vii inverted on 5th
- case 2:
- output[0] = {-7} # fourth
- if (rval)
- output[1] = {-5} # fifth
- else
- output[1] = {-3} # sixth
- end
- output[2] = {-1} # seventh
- end
- # 3rd, return major 6/7 inverted on 5rd
- case 4:
- output[0] = {-5} # 5th
- if (rval)
- output[1] = {-3} # 6th
- else
- output[1] = {-1} # 7th
- end
- output[2] = 0 #unison
- end
- # 4th, return Dom/half-dim. Dom rooted on dom unison,
- # half-dim rooted on 7th
- case 5:
- if (rval)
- output[0] = {-5} # 5th
- else
- output[0] = {-3} # 6th
- end
- output[1] = {-1} #7th
- output[2] = 2 # 2nd
- end
- # 5th, return major chord
- case 7:
- if (rval)
- output[0] = {-3} # 6th
- else
- output[0] = {-1} # 7th
- end
- output[1] = 0 # unison
- output[2] = 4 # 3rd
- end
- # 6th, return half/dim OR minor 2nd.
- case 9:
- if (rval)
- output[0] = {-1} # 7th
- else
- output[0] = 0
- end
- output[1] = 2 # 2nd
- output[2] = 5 # 4th
- end
- # 7th, return major or Dom7
- case 11:
- if (rval)
- # major
- output[0] = 0
- output[1] = 4 #3rd
- output[2] = 7 #5th
- else
- # dom7
- output[0] = 2 #2nd
- output[1] = 5 #4th
- output[2] = 7 #5th
- end
- end
- default:
- void printf("unknown offset\n")
- end
- end
- end
-
- # TEST ROUTINES
- # commented out at the moment.
- ###############################################################
-
- #int harmChord[3]
- #riff testHarmonize()
- # int i
- # int scaleIndex
- # int melOffset
- #
- # for ( scaleIndex = 6; scaleIndex >= 0; scaleIndex--)
- # # pass the following
- # # 1. pointer to output vector of size 3
- # # 2. size of scale
- # # 3. pointer to scale offset row
- # # 4. current roff value
- # melOffset = baseScale[IONIAN][scaleIndex]
- # void chordHarmonize(&harmChord, melOffset, &chordNotes[Major6], chordSizes[Major6])
- # # print out chord from bass to melody
- # for ( i = 0; i < 3; i++)
- # void printf("%n,", C+harmChord[i])
- # C+harmChord[i] 0,q 100
- # end
- # void printf("%n\n",C+melOffset)
- # C+melOffset q 100
- # end
- #end
- #
- #int aChord[3]
- #riff testModalHarmonize()
- # int i
- # int scaleIndex
- #
- # for ( scaleIndex = 6; scaleIndex >= 0; scaleIndex--)
- # # pass the following
- # # 1. pointer to output vector of size 3
- # # 2. size of scale
- # # 3. pointer to scale offset row
- # # 4. current roff value
- # void modalHarmonize(&aChord, scaleSizes[DORIAN], &baseScale[DORIAN], baseScale[DORIAN][scaleIndex])
- # for ( i = 0; i < 3; i++)
- # void printf("%n,", C+aChord[i])
- # C+aChord[i] 0,q 100
- # end
- # void printf("%n\n",C+baseScale[DORIAN][scaleIndex])
- # C+baseScale[DORIAN][scaleIndex] q 100
- # end
- #end
- #
- #int hChord[3]
- #riff testParallelHarmonize()
- # int i
- # int scaleIndex
- # int melOffset
- # int lastMelOffset
- # int difference
- #
- # # play first chord
- # lastMelOffset = baseScale[IONIAN][6]
- # hChord[2] = baseScale[IONIAN][4]
- # hChord[1] = baseScale[IONIAN][2]
- # hChord[0] = baseScale[IONIAN][0]
- # for ( i = 0; i < 3; i++)
- # void printf("%n,", C+hChord[i])
- # C+hChord[i] 0,q 100
- # end
- # void printf("%n\n",C+lastMelOffset)
- # C+lastMelOffset q 100
- #
- # for ( scaleIndex = 5; scaleIndex >= 0; scaleIndex--)
- # # pass the following
- # # 1. pointer to output vector of size 3
- # # 2. size of scale
- # # 3. pointer to scale offset row
- # # 4. current roff value
- # melOffset = baseScale[IONIAN][scaleIndex]
- # difference = melOffset - lastMelOffset
- # void parallelHarmonize(&hChord, melOffset, difference)
- # for ( i = 0; i < 3; i++)
- # void printf("%n,", C+hChord[i])
- # C+hChord[i] 0,q 100
- # end
- # void printf("%n\n",C+baseScale[IONIAN][scaleIndex])
- # C+baseScale[IONIAN][scaleIndex] q 100
- # lastMelOffset = melOffset
- # end
- #end
-
- #int rChord[3]
- #vco testRoot()
- # int i
- # int index
- # int melOffset
- #
- #
- # for ( index = 0; index < 7; index++)
- # melOffset = baseScale[IONIAN][index]
- # void majorHarmonize(&rChord, melOffset)
- # for ( i = 0; i < 3; i++)
- # void printf("%n,", C+rChord[i])
- # C+rChord[i] 0,q 100
- # end
- # void printf("%n\n",C+melOffset)
- # C+melOffset q 100
- # end
- #end
-